<?php

namespace plugins\module_config\controller;

use app\common\lib\file_operate\FileOperate as FO; //引入此类

use app\common\lib\file_operate\MakeZip;
use app\common\lib\user_operate\ModuleOperate as MO;
use app\common\lib\user_operate\PluginOperate;
use app\common\model\PluginDbTableModel;
use cmf\controller\PluginAdminBaseController;
use plugins\module_config\model\PluginApiIndexModel as Model;
use think\Db;

/**







 * 安装检查控制器







 */

class InstallCheckController extends PluginAdminBaseController
{

    /**

     * 配置检查项

     */

    protected $checkItem = [

        0 => [

            'item' => 'moduleFileExist',

        ],

    ];

    /**

     * 获取检查项

     * @return [type] [description]

     */

    public function getCheckItem()
    {

        return $this->checkItem;

    }

    /**

     * 开启检查项

     * @param  integer $index [description]

     * @return [type]         [description]

     */

    public function check($index = 0)
    {

        $data = $this->request->post();

        $param = isset($data['param']) ? $data['param'] : [];

        $method = $this->checkItem[$index]['item'];

        return call_user_func_array([$this, $method], $param);

    }

    /**

     * 检查文件是否存在

     */

    public function moduleFileExist($plugin_name = '', $module_name = '', $id = '')
    {

        $data = $this->request->param();

        //模块文件检查

        self::returnStr('模块文件检查', '模块文件不存在', 201);

        self::returnStr('执行模块文件下载', '模块文件下载中，请稍后', 201, cmf_plugin_url('ModuleConfig://InstallCheck/download') . '?plugin_name=' . $plugin_name . '&module_name=' . $module_name . '&id=' . $id);

        return zy_json_echo(true, self::$returnStrArray);

    }

    /**







     * 文件下载







     */

    public function download($plugin_name = '', $module_name = '', $id = '')
    {

        //获取下载链接

        $po = new PluginOperate();

        $url = $po->getDownloadUrl($id)['data'];

        $pluginsPath = PLUGINS_PATH;

        //执行下载

        $fo = new FO();

        $res = $fo->fileDownload($url, $pluginsPath);

        if (isset($res['status']) && $res['status'] == 'error') {

            self::returnStr('模块文件下载', $res['message'], 102);

            //安装失败卸载插件

            // $this->uninstall( $plugin_name , $module_name , true );

            return zy_json_echo(true, self::$returnStrArray);

        }

        self::returnStr('模块文件下载', '下载完成');

        self::returnStr('模块文件下载', '文件解压中', 201, cmf_plugin_url('ModuleConfig://InstallCheck/unZip') . '?plugin_name=' . $plugin_name . '&module_name=' . $module_name . '&file_name=' . $res['data']);

        return zy_json_echo(true, self::$returnStrArray);

    }

    /**







     * 执行文件解压







     */

    public function unZip($plugin_name = '', $module_name = '', $file_name = '')
    {

        $mz = new MakeZip();

        $outPath = PLUGINS_PATH;

        self::returnStr('模块文件解压', $outPath);

        $res = $mz->unZip($file_name, $outPath);

        if ($res['status'] == 'error') {

            self::returnStr('模块文件解压', $res['message'], 101);

            return zy_json_echo(true, self::$returnStrArray);

        }

        self::returnStr('模块文件解压', $res['message']);

        // self:returnStr('安装插件','插件安装中',201,cmf_plugin_url('ModuleConfig://InstallCheck/install').'?name='.$name)

        self::returnStr('模块文件移动', '文件移动中', 201, cmf_plugin_url('ModuleConfig://InstallCheck/moveFile') . '?plugin_name=' . $plugin_name . '&module_name=' . $module_name);

        return zy_json_echo(true, self::$returnStrArray);

    }

    /**







     * 获取文件目录







     */

    public function getFileDir($path, &$relationArr)
    {

        if (!is_dir($path) || !is_array($relationArr)) {

            return false;

        }

        if ($dh = opendir($path)) {

            while ($file = readdir($dh)) {

                if (in_array($file, array('.', '..', null))) {

                    continue;

                }

                //无效文件，重来

                if (is_dir($path . DS . $file)) {

                    $relationArr[$file] = array(

                        'file_name' => $file,

                        'is_dir'    => true,

                        'children'  => array(),

                    );

                    $this->getFileDir($path . DS . $file, $relationArr[$file]['children']);

                } else {

                    $extension = strchr($file, '.');

                    $relationArr[$file] = array(

                        'file_name' => $file,

                        'is_dir'    => false,

                        'children'  => array(),

                    );

                }

            }

        }

    }

    /**







     * 记录安装日志







     */

    public function record($plugin_name, $module_name, $data, $tags)
    {

        $plugin_name = cmf_parse_name($plugin_name);

        $rec = getModuleConfig($module_name, 'config/install', $plugin_name . '.log');

        $rec = json_decode($rec, true);

        $rec[$tags] = $data;

        saveModuleConfigData($module_name, 'config/install', $plugin_name . '.log', $rec);

    }

    /**



     * 移动文件



     */

    public function moveFile($plugin_name = '', $module_name = '')
    {

        $fo = new FO();

        //插件目录

        $dir_path = ROOT_PATH . 'public/plugins/' . cmf_parse_name($plugin_name);

        //模块目录

        $module_path = ROOT_PATH . 'public/plugins/' . cmf_parse_name($module_name);

        $relationArr = array(

            $dir_path => array(

                'file_name' => $dir_path,

                'is_dir'    => true,

                'children'  => array(),

            ),

        );

        //获取文件目录

        $this->getFileDir($dir_path, $relationArr[$dir_path]['children']);

        $child = $relationArr[$dir_path]['children'];

        //获取插件最外层文件名

        $ks = array_keys($child);

        //安装日志

        $record = [];

        foreach ($ks as $k1 => $v1) {

            //插件目录
            $d = $dir_path . '/' . $v1;

            //模块目录
            $m = $module_path . '/' . $v1;

            $e = $child[$v1]; //文件

            //存入记录不带ROOT_PATH

            $cunr = 'public/plugins/' . cmf_parse_name($module_name) . '/' . $v1;

            //config 文件移动tag

            if ($v1 == 'config') {

                //判断是否存在tag文件
                if (in_array('tag', array_keys($e['children']))) {

                    foreach ($e['children']['tag']['children'] as $tag_k => $tag_k) {

                        $tgs = $d . '/tag/' . $tag_k;

                        $mgs = $m . '/tag/' . $tag_k;
                        //添加记录
                        $record[] = $cunr . '/tag/' . $tag_k; //$mgs;

                        $fo->moveFile($tgs, $mgs);
                    }
                }

                continue;
            }

            if ($v1 == 'view') {

                if ($e['is_dir'] == true) {

                    foreach (array_keys($e['children']) as $k2 => $v2) {

                        if ($v2 == 'public') {
                            $this->movePublic($d,$m,$e['children']['public'],$record,$cunr,$fo);

                            continue;
                        }

                        $ds = $d . '/' . $v2;

                        $ms = $m . '/' . $v2;

                        $record[] = $cunr . '/' . $v2; //$ms;

                        if (is_dir($ds)) {
                            $fo->recurse_copy($ds, $ms);
                        } else {
                            $fo->moveFile($ds, $ms);
                        }
                    }
                }

                continue;
            }

            //如果是目录，则移动目录
            if ($e['is_dir'] == true) {

                foreach (array_keys($e['children']) as $k2 => $v2) {

                    $ds = $d . '/' . $v2;

                    $ms = $m . '/' . $v2;

                    $record[] = $cunr . '/' . $v2; //$ms;

                    if (is_dir($ds)) {

                        $fo->recurse_copy($ds, $ms);

                    } else {

                        $fo->moveFile($ds, $ms);

                    }

                }

            }

        }

        //记录安装
        $this->record($plugin_name, $module_name, $record, 'file_name');

        self::returnStr('模块文件移动', '移动成功');

        self::returnStr('执行插件安装', '安装中', 201, cmf_plugin_url('ModuleConfig://InstallCheck/install') . '?plugin_name=' . $plugin_name . '&module_name=' . $module_name);

        return zy_json_echo(true, self::$returnStrArray);
    }


    /**
     * 移动公共文件
     */
    private function movePublic($plugin_path,$module_path,$dir=[],&$record,$cunr,&$fo)
    {
        if ($dir['is_dir'] == true) {

            $plugin_path .= '/'.$dir['file_name'];
            $module_path .= '/'.$dir['file_name'];
            $cunr .= '/'.$dir['file_name'];

            foreach ($dir['children'] as $key => $value) {

                $this->movePublic($plugin_path,$module_path,$value,$record,$cunr,$fo);
            }
        } else {
            $p_p = $plugin_path .'/'.$dir['file_name'];
            $m_p = $module_path .'/'.$dir['file_name'];

            $record[] = $cunr . '/' . $dir['file_name'];

            $fo->moveFile($p_p, $m_p);
        }

        return 1;
    }





    /**
     * 执行安装
     */
    public function install($plugin_name = '', $module_name = '')
    {

        //移动菜单

        $this->moveMenu($plugin_name, $module_name);

        //移动引入文件配置

        $this->moveHtml($plugin_name, $module_name);

        //添加表字段

        $this->addTableFields($plugin_name, $module_name);

        //添加插件表

        $this->addDbTable($plugin_name, $module_name);

        //删除插件目录

        $fo = new FO();

        $dir_path = ROOT_PATH . 'public/plugins/' . cmf_parse_name($plugin_name);

        try {

            $fo->deldir($dir_path); //删除旧目录

        } catch (\Exception $e) {

            self::returnStr('执行安装', '安装失败，插件目录不存在,请检查压缩包是否正确', 202);

            //安装失败卸载插件

            $this->uninstall($plugin_name, $module_name, true);

            return zy_json_echo(true, self::$returnStrArray);

        }

        self::returnStr('执行安装', '安装成功');

        return zy_json_echo(true, self::$returnStrArray);

    }

    /**



     * 移动引入html配置



     */

    public function moveHtml($plugin_name, $module_name)
    {

        //1.读出配置文件内容

        //2.读出之后写入html.json 文件中

        //记录

        $record = [];

        $p_config = getModuleConfig($plugin_name, 'config', cmf_parse_name($plugin_name) . '.json');

        $p_config = json_decode($p_config, true);

        if (empty($p_config['html'])) {

            return true;

        }

        $m_config = getModuleConfig($module_name, 'config', 'html.json');

        $m_config = json_decode($m_config, true);

        if (empty($m_config)) {

            $m_config['html'] = $p_config['html'];

        } else {

            $m_config['html'] = array_merge($m_config['html'], $p_config['html']);

        }

        $record = $m_config;

        //记录安装

        $this->record($plugin_name, $module_name, $record, 'html');

        saveModuleConfigData($module_name, 'config', 'html.json', $m_config);

    }

    /**



     * 安装表



     */

    public function addDbTable($plugin_name, $module_name)
    {

        $dbTable = new PluginDbTableModel();

        $res = $dbTable->installDataTable(cmf_parse_name($plugin_name));

        //获取安装表名

        $sqlFileDirectory = PLUGINS_PATH . cmf_parse_name($plugin_name) . '/data';

        if (!file_exists($sqlFileDirectory)) {

            return false;

        }

        $directorys = scandir($sqlFileDirectory);

        $directorys = array_diff($directorys, ['.', '..']);

        $directorys = array_merge($directorys);

        foreach ($directorys as $key => $value) {

            $directorys[$key] = str_replace(strrchr($value, "."), "", $value);

        }

        $record = $directorys;

        //记录安装

        $this->record($plugin_name, $module_name, $record, 'table');

        if ($res) {

            return true;

        }

    }

    /**







     * 移动菜单







     */

    public function moveMenu($plugin_name, $module_name)
    {

        //记录

        $record = [];

        $p_config = getModuleConfig($plugin_name, 'config', cmf_parse_name($plugin_name) . '.json');

        $p_config = json_decode($p_config, true);

        if (empty($p_config['nav'])) {

            return true;

        }

        $m_config = getModuleConfig($module_name, 'config', 'nav.json');

        $m_config = json_decode($m_config, true);

        if (empty($m_config)) {

            $m_config['nav'] = $p_config['nav'];

        } else {

            $m_config['nav'] = array_merge($m_config['nav'], $p_config['nav']);

        }

        $record = $m_config;

        //记录安装

        $this->record($plugin_name, $module_name, $record, 'nav');

        saveModuleConfigData($module_name, 'config', 'nav.json', $m_config);

    }

    /**







     * 添加表字段







     */

    public function addTableFields($plugin_name, $module_name)
    {

        $record = [];

        $mo = new MO();

        $p_config = getModuleConfig($plugin_name, 'config', cmf_parse_name($plugin_name) . '.json');

        $p_config = json_decode($p_config, true);

        if (empty($p_config['sql'])) {

            return true;

        }

        $record = $p_config['sql'];

        foreach ($p_config['sql'] as $key => $value) {

            $add = $key . " "; //字段名称

            $add .= $value['type'] . '(' . $value['length'] . ') '; //类型

            $default = !empty($value['default']) ? $value['default'] : 'NULL';

            $add .= "DEFAULT " . $default . " "; //默认值

            $add .= "COMMENT '" . $value['desc'] . "'"; //字段注释

            if (!empty($value['table_name'])) {

                $table_name = $value['table_name'];

            } else {

                $model = new Model();

                $table_name = $model->getTableName($module_name);

            }

            //判断字段是否存在

            $is_in = Db::query("SELECT column_name FROM information_schema.columns WHERE table_name ='{$table_name}' AND column_name='{$key}';");

            if (!empty($is_in)) {

                //存在 修改

                Db::execute("ALTER TABLE `$table_name` MODIFY $add");

            } else {

                //不存在 添加

                try {

                    Db::execute("ALTER TABLE `$table_name` ADD $add;");

                } catch (\Exception $f) {

                    self::returnStr('执行安装', $table_name . '表的' . $key . '字段添加失败:' . $f->getMessage(), 202);

                    //安装失败卸载插件

                    $this->uninstall($plugin_name, $module_name, true);

                    return zy_json_echo(true, self::$returnStrArray);

                }

            }

        }

        //记录安装

        $this->record($plugin_name, $module_name, $record, 'sql');

    }

    /**







     * 检查文件是否存在







     */

    private function checkModuleFileIsExist($symbol, $file = '')
    {

        $fileName = PLUGINS_PATH . DS . cmf_parse_name($symbol);

        if (!empty($file)) {

            $fileName = $fileName . DS . $file;

        }

        if (!file_exists($fileName)) {

            return false;

        }

        return $fileName;

    }

    /**







     * 状态返回







     * @return [type] [description]







     */

    protected static $returnStrArray = [];

    private static function returnStr($item = '', $msg = '', $code = 200, $operate = 'empty')
    {

        $data = [

            'item'    => $item,

            'msg'     => $msg,

            'code'    => $code,

            'operate' => $operate,

        ];

        self::$returnStrArray[] = $data;

    }

    /**







     * 卸载插件







     */

    public function uninstall($plugin_name, $module_name, $sysbom = false)
    {

        $data = $this->request->param();

        $plugin_name = !empty($plugin_name) ? $plugin_name : $data['plugin_name'];

        $module_name = !empty($module_name) ? $module_name : $data['module_name'];

        //读安装日志文件

        $config = getModuleConfig($module_name, 'config/install', cmf_parse_name($plugin_name) . '.log');

        $config = json_decode($config, true);

        $tags = array_keys($config);

        foreach ($tags as $k => $v) {

            switch ($v) {

                case 'file_name':

                    $this->unfileName($module_name, $config['file_name']);

                    break;

                case 'nav':

                    $this->unnav($module_name, $plugin_name);

                    break;

                case 'sql':

                    $this->unsql($module_name, $plugin_name, $config['sql']);

                    break;

                case 'table':

                    $this->unDbTable($module_name, $plugin_name, $config['table']);

                    break;

                case 'html':

                    $this->unhtml($module_name, $plugin_name, $config['html']);

                    break;

                default:

                    # code...

                    break;

            }

        }

        $record_file = ROOT_PATH . 'public/plugins/' . cmf_parse_name($module_name) . '/config/install/' . cmf_parse_name($plugin_name) . '.log';

        unlink($record_file);

        if ($sysbom == true) {

            //卸载目录

            $record_file = ROOT_PATH . 'public/plugins/' . cmf_parse_name($plugin_name);

            if (file_exists($record_file)) {

                $fo = new FO();

                $fo->deldir($record_file); //删除旧目录

            }

            return ['status' => true, 'message' => '卸载成功', 'code' => 200];

        }

        return $this->success('卸载成功');

    }

    /**







     * 删除文件







     */

    private function unfileName($module_name, $config)
    {

        if (empty($config)) {

            return true;

        }

        $fo = new FO();

        foreach ($config as $key => $value) {

            $v = ROOT_PATH . $value;

            //判断文件目录是否存在

            if (!file_exists($v)) {

                continue;

            }

            if (is_dir($v)) {

                $fo->deldir($v); //删除旧目录

            } else {

                unlink($v);

            }

        }

    }

    /**



     * 删除菜单



     */

    public function unnav($module_name, $plugin_name)
    {

        $config = getModuleConfig($module_name, 'config', 'nav.json');

        $config = json_decode($config, true);

        $da['nav'] = [];

        foreach ($config['nav'] as $key => $value) {

            if ($value['plugin'] == cmf_parse_name($plugin_name)) {

                //需要卸载的

                continue;

            }

            $da['nav'][] = $value;

        }

        saveModuleConfigData($module_name, 'config', 'nav.json', $da);

    }

    /**



     * 删除html.json



     */

    public function unhtml($module_name, $plugin_name)
    {

        $config = getModuleConfig($module_name, 'config', 'html.json');

        $config = json_decode($config, true);

        $da['html'] = [];

        foreach ($config['html'] as $key => $value) {

            if ($value['plugin'] == cmf_parse_name($plugin_name)) {

                //需要卸载的

                continue;

            }

            $da['html'][] = $value;

        }

        saveModuleConfigData($module_name, 'config', 'html.json', $da);

    }

    /**







     * 删除字段







     */

    public function unsql($module_name, $plugin_name, $config)
    {

        if (empty($config)) {

            return true;

        }

        foreach ($config as $key => $value) {

            try {

                if (!empty($value['table_name'])) {

                    $table_name = $value['table_name'];

                } else {

                    $model = new Model();

                    $table_name = $model->getTableName($module_name);

                }

                Db::execute("ALTER TABLE `$table_name` drop column `$key`;");

            } catch (\Exception $e) {

                continue;

            }

        }

    }

    /**







     * 删除插件表







     */

    public function unDbTable($module_name, $plugin_name, $config)
    {

        $dropTableSql = " DROP TABLE IF EXISTS ";

        foreach ($config as $key => $value) {

            $dropTableSqls = $dropTableSql . $value;

            Db::execute($dropTableSqls);

        }

    }

}
